/***************************************************************************
                          parser.cpp  -  description
                             -------------------
    begin                : Mon May 6 2002
    copyright            : (C) 2002 by Michiel Visser
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
#include "parser.h"
#include "regexp.h"

#include<math.h>

using namespace Expression;

inline bool isIdentifier(char c)
{
	return (c>='a'&&c<='z') || (c>='A'&&c<='Z') || c=='_';
}

TyleParser::TyleParser(unsigned char *pos, EPtr &result, void *returnObjectSpace):
  m_pos(pos),
  m_c(0),
  m_line(1),
  m_s(0x100000),
	m_dynamic(0)
{
	session.m_funcLevel=0;
  try
  { nextChar();
    nextWord();
    result = parseSequence();
    skipSpaces();
    if (m_s[0]!='\0') 
		{	throw("Could not parse completely.");
		}
  }
  catch (const char *error)
  { if (returnObjectSpace)
		{	char s[256];
	 		sprintf(s,"Parse error at line %i: %s\n",m_line, (char *)error);
	 		new (returnObjectSpace) StringObject(s);
		}
		result=EPtr();
  }
}

void TyleParser::nextChar()
{ 
	while (m_pos[0]=='/')
  { if (m_pos[1]=='*')
    { for (m_pos+=2; *m_pos!=0; m_pos++)
      { if (*m_pos==10) m_line++;
        if (*m_pos=='*' && m_pos[1]=='/') { m_pos+=2; break; }
      }
    } else if (m_pos[1]=='/')
    { for (m_pos+=2; *m_pos!=0; m_pos++)
      { if (*m_pos==10) { m_line++; m_pos++; break; }
      }
    } else break;
  }
  m_c=*(m_pos++);
	if (m_c==10) m_line++;
}

void TyleParser::nextWord()
{ int pos = 0;
#define SCP { storeChar(pos); nextChar(); }
#define SRCP { storeChar(pos); nextRawChar(); }
  skipSpaces();
  if (m_c=='\"')
  { do
    { if (m_c==0) throw("String not finished.");
    	else if (m_c<32) { nextRawChar(); continue; }
      else if (m_c=='\\')
      {	nextRawChar();
	    	m_c=parseEscapeChar(m_c,m_pos);
			}
      SRCP;
    } while (m_c!='\"');
    m_strlen=pos-1;
    nextChar();
  }
  else if (m_c=='\'')
  {	m_c='\"';
	  do
    { if (m_c==0) throw("String not finished.");
      SRCP;
    } while (m_c!='\'');
    m_strlen=pos-1;
    nextChar();
  }
  else if (m_c=='`')
  { do
    { if (m_c==0) throw("Regexp not finished.");
    	else if (m_c<32) { nextRawChar(); continue; }
      else if (m_c=='\\')
      {	SRCP;
        if (m_c==0) throw("Escape sequence not finished.");
      }
      SRCP;
    } while (m_c!='`');
    m_strlen=pos-1;
    unsigned char mask=0;
    for(;;)
    { nextRawChar();
      if      (m_c=='i') mask|=1;
      else if (m_c=='m') mask|=2;
      else if (m_c=='o') mask|=4;
      else break;
    }
    m_s[pos++]=mask;
  }
  else if (m_c>' ')
  { short omc=m_c;
    SCP
    switch(omc)
    {
		case '#': while(m_c!=';' && m_c!=',' && m_c!=0) SCP; break;
	  case '.': if (m_c=='!'||m_c=='?'||m_c=='*'||m_c=='@') SCP else if (m_c=='.' && m_pos[0]=='.') {SCP; SCP;} break; 
	  case ':': if (m_c=='!'||m_c=='@') SCP else if (m_c=='+'||m_c=='-') { SCP if (m_c=='=') SCP } break;
	  case '|': if (m_c=='|') SCP           if (m_c=='=') SCP break;
	  case '&': if (m_c=='&') SCP           if (m_c=='=') SCP break;
	  case '+': if (m_c=='<'||m_c=='>'||m_c=='*') SCP if (m_c=='=') SCP break;
	  case '<': if (m_c=='<') SCP           if (m_c=='=') SCP break;
	  case '>': if (m_c=='>') SCP           if (m_c=='=') SCP break;
	  case '-': if (m_c=='>') SCP else { if (m_c=='*') SCP if (m_c=='=') SCP break; }
	  case '%': if (m_c=='=') { SCP break; } // else fall through
	  case '?': if (m_c=='!') SCP break;
	  case '@': if (m_c=='@') SCP break;
	  case '*': if (m_c=='!') { SCP break; } // else fall through
	  case '^':
	  case '/': if (m_c=='=') SCP break;
	  case '[': if (m_c==':' && m_pos[0]=='-') SCP break;
	  case '=': if (m_c=='=' || m_c=='>' ) SCP break;
	  case '!': if (m_c=='=' && m_pos[0]!='=') SCP break;
	  case '{': if (m_c==':') SCP break;
		default:
			if ( omc>='0' && omc<='9')
			{	if (omc=='0' && (m_c=='x'||m_c=='X'))
				{	do { SCP; } while ((m_c>='0' && m_c<='9') || (m_c>='a' && m_c<='f') || (m_c>='A' && m_c<='f'));
				}
				else if (omc=='0' && (m_c=='b'||m_c=='B'))
				{	do { SCP; } while ((m_c=='0' || m_c=='1'));
				}
				else if (omc=='0' && (m_c=='o'||m_c=='O'))
				{	do { SCP; } while ((m_c>='0' && m_c<='7'));
				}
				else
				{	while (m_c>='0' && m_c<='9') SCP;
					if (m_c=='.' && m_pos[0]>='0' && m_pos[0]<='9')
					{	SCP; 
						do { SCP; } while (m_c>='0' && m_c<='9');
					}
					if (m_c=='e'||m_c=='E')
					{	SCP;
						if (m_c=='-'||m_c=='+') SCP;
						while (m_c>='0' && m_c<='9') SCP;
					}
				}
			}
			else if ( isIdentifier(omc) )
  		{ while ((m_c>='0' && m_c<='9') || isIdentifier(m_c) ) SCP;
    	}
			break;
  	}
	}
  m_s[pos]=0;
#undef SCP
}

bool TyleParser::parseWord(char *word)
{
  if (strcmp(m_s,word)!=0)
  { return false;
  }
  nextWord();
  return true;
}

EPtr TyleParser::parseString()
{
  Object *o;
  if (m_s[0]=='`')
  { o=NEW_OBJ RegExpObject(((unsigned char *)m_s)+1,m_strlen,((unsigned char *)m_s)[m_strlen+1]);
  	((RegExpObject *)o)->parse();
  }
  else if (m_s[0]!='\"') return EPtr();
  else
  { o=NEW_OBJ StringObject(((char *)m_s)+1,m_strlen);
  }
  EPtr res;
  new (res) ConstExpr(o);
  nextWord();
  return res;
}

void TyleParser::addStructElem(List<StructElem> &ses, TypePtr parent, String name, TypePtr type, TypeFunc *func)
{
	int i=ses.length();
	new (ses.end()) StructElem(name, type);
	if (func)
	{	if (func->isPreTypeSelection())
			TypeFunc *f=new (*structing.funcs) TypeToStructElemAssignmentOnce (parent, i, func);
		else
			TypeFunc *f=new (*structing.funcs) TypeToStructElemAssignment (parent, i, func);
		structing.funcs++;
	}
}

TypePtr TyleParser::parseType(/*out*/ TypeFunc *&funcOut)
{
  TypePtr p(parseStructConcat(funcOut));

  if (parseWord("=>"))
  { 
    TypePtr np;
		new (np) Type();
		if (!!funcOut)
		{ new (*structing.funcs) TypeToStructElemAssignment (np, 0, funcOut);
			structing.funcs++;
		}
		TypePtr p2(parseType(funcOut));
		if (!!funcOut)
		{ new (*structing.funcs) TypeToStructElemAssignment (np, -1, funcOut);
			structing.funcs++;
			funcOut=0;
		}
		List<StructElem> elems;
		new (elems) StructElem(String(), p);
		np->set(elems, false);
		np->m_childType=p2;
    return np;
  }
  return p;
}
TypePtr TyleParser::parseStructConcat(/*out*/ TypeFunc *&funcOut)
{
	TypePtr p(parseTypeAssignment(funcOut));
	if (parseWord("+"))
	{
		if (!funcOut)
		{	funcOut = new TypeSelection(p);
			p = TypePtr();
		}
		do 
		{	TypeFunc *func2;
			TypePtr p2(parseTypeAssignment(func2));
			if (!func2)
			{	func2 = new TypeSelection(p2);
			}
			funcOut = new StructConcat(funcOut,func2);
		} while (parseWord("+"));
	}
	return p;
}

TypePtr TyleParser::parseTypeLeftVal(/*out*/ TypeFunc *&funcOut)
{
	funcOut=0;
	TypePtr p;
	String name((char *)m_s);	
	nextWord();
	p = session.findType(name);
	if (!p)
	{ funcOut = new PreTypeSelection(name);
		//old!-> todo p = session.newTypeEntry(name);
  }
	if (parseWord("."))
	{ if (!!p)
			funcOut = new TypeSelection(p);
		p=TypePtr();
		do
		{	String name((char *)m_s);	//todo: add word check
			nextWord();
			funcOut=new StructIndexing(funcOut,name);
		} while (parseWord("."));
	}
	return p;
}
TypePtr TyleParser::parseTypeAssignment(/*out*/ TypeFunc *&funcOut)
{
	funcOut=0;
	if ( isIdentifier(m_s[0]))
  { TypePtr p = parseTypeLeftVal(funcOut);
		if (parseWord("="))
		{	TypeFunc *func2;
			if (!funcOut)
				funcOut = new TypeSelection(p); 
			TypePtr p2 (parseType(func2));
			if (!!p2)
				func2 = new TypeSelection(p2); 
/*			if (!!p)
			{	new (*structing.funcs) TypeAssignment(funcOut, func2);
				funcOut=0;
			}
			else
				funcOut = new TypeAssignment(funcOut, func2);*/
			funcOut = new TypeAssignment(funcOut, func2);
			return TypePtr();
		}
		return p;
	}
	else return parseTypeLiteral(funcOut);
}

TypePtr TyleParser::parseTypeLiteral(TypeFunc *&funcOut)
{
	funcOut = 0;
	TypePtr p;
  List<StructElem> ses;
  if (parseWord("{"))
  {	bool allowDynamicElems=false;
    new (p) Type(allowDynamicElems);
    while (!parseWord("}"))
  	{	
    	if (parseWord("..."))
    	{ allowDynamicElems=true;
    	  if (!parseWord("}")) throw("Expected '}' after '...'");
    	  break;
  	  }
	  	TypeFunc *subFunc;
			TypePtr subType(parseTypeSelection(subFunc));
	  	if (!isIdentifier(m_s[0])) throw("Expected identifier.");
      String m_sc((char *)m_s);
			addStructElem(ses,p,m_sc,subType,subFunc);
	  	nextWord();
	  	if (parseWord("}")) break;
	  	if (!parseWord(","))
	  	{ throw("Expected ',' or '}'.");
	  	}
  	}
		p->set(ses,allowDynamicElems);
  }
  else if (parseWord(":"))
  { p=parseType(funcOut);
		TypePtr np;
		new (np) Type(p);
		if (!!funcOut)
		{ new (*structing.funcs) TypeToStructElemAssignment (np, -1, funcOut);
			structing.funcs++;
			funcOut=0;
		}
		return np;
  }
  else if (parseWord("("))
  { p=parseType(funcOut);
  	if (!parseWord(")"))
  	{ throw("Expected ')'.");
  	}    
  }
  return p;
}


TypePtr TyleParser::parseTypeSelection(TypeFunc *&funcOut)
{	
	funcOut=0;
  TypePtr t;
  if (parseWord("["))
  {	t=parseType(funcOut);
  	if (!parseWord("]")) throw("Missing ']' of Type definition.");
  }
  return t;
}
static String concatStrings(List<String> &txt)
{
	int l=0;
  FOREACH(List<String>,txt,i) l+=i->length();
  String str(l+1);
  char *sp=str;
  FOREACH(List<String>,txt,i)
  { int l=i->length();
    memcpy(sp,(char *)*i,l);
    sp+=l;
  }
	*sp=' ';
	return str;
}
EPtr TyleParser::parseTypeSelectionExpr()
{
	EPtr res;
	List<TypeFunc> structFuncs;
	structing.funcs=&structFuncs;
	TypeFunc *func;
	TypePtr type(parseTypeSelection(func));
	if (!!type)
	{	func = new TypeSelection(type);
	}
  if(func)
	{ new (res) TypeSelectionExpr(func,structFuncs);
  }
  return res;
}

EPtr TyleParser::parseVar()
{
	EPtr res;
  if (parseWord("$"))
  { int depth;
		m_dynamic=1;
    if (m_s[0]>='a'&&m_s[0]<='z')
    { int d=m_s[0]-'a';
	    int l=session.m_funcLevel+d;
	    if (d<3 && l<4)
	    	res = session.m_exprAbsDollarVars[d][l];
	    else
	    	new (res) DollarVarExpr(l, int('a')+d);
      nextWord();
    } 
    else if (parseDigits(m_s,depth)>0)
    { if (depth==0) throw("Variable $0 is not valid, use: $,$2,$3...");
      nextWord();
      if (depth<4)
      	res = session.m_exprDollarVars[depth-1];
      else
      	new (res) DollarVarExpr(depth-1,int('0')+depth);
    }
    else
      new (res) DollarVarExpr(0,0);
  }
  else
  { bool localFind = parseWord(".");
    unsigned char c=m_s[0];
    if ( isIdentifier(c) )
    { m_dynamic=1;
			res = session.findOrInsert((char *)m_s,localFind);
      nextWord();
    }
    else if (localFind)
      throw("Variable expected after '.'.");
  }
  return res;
}

int TyleParser::parseDigits(unsigned char *p, /*out */int &result, int base)
{
  result=0;
  int count=0;
  for(;;)
  { int v = hexDigitToValue(*p);
	  if (v<0 || v>=base) break;
	  result = result * base + v;
    count++;
    p++;
  }
  return count;
}

unsigned char *TyleParser::parseInt(unsigned char *p, int &base, /*out*/ int &result)
{	
	if (*p<'0' || *p>'9') { result=0; return 0; }
  if (*p=='0' && p[1]!=0 && p[1]!='.' && (p[1]<'0' || p[1]>'9'))
  { if (p[1]=='x' || p[1]=='X')      { p+=2; base=16; }
	  else if (p[1]=='o' || p[1]=='O') { p+=2; base=8; }
	  else if (p[1]=='b' || p[1]=='B') { p+=2; base=2; }
	  else { result=0; return 0; }
	} else base=10;
  p+=parseDigits(p,result,base);
  return p;
}
  
EPtr TyleParser::parseNumber()
{
  int result;
  int base;
  EPtr res;
  unsigned char *p=m_s;
  p=parseInt(p, base, result);
  if (!p)
  	return EPtr();
	int r2=0,c2=0,r3=0, isFloat=0;
  if (*p=='.')
  {	if ((c2=parseDigits(++p,r2,base))==0) { throw("Missing digits after '.'"); return EPtr(); }
		p+=c2;
		isFloat=1;
	}
	if (*p=='e'||*p=='E')
	{	int esign=1;
		if (p[1]=='-') { esign=-1; p++; }
		else if (p[1]=='+') p++;
		parseDigits(p+1,r3,10);
		r3*=esign;
		isFloat=1;
	}
	if (isFloat)
    new (res) ConstExpr(NEW_OBJ FloatObject((result + r2*pow(base,-c2))*pow(10,r3) ));
  else
  {	if (result>=0 && result<4)
  		res=session.m_exprNumbers[result];
  	else
    new (res) ConstExpr(NEW_OBJ IntegerObject(result));
	}
    
	nextWord();
  return res;
}

EPtr TyleParser::parseHash()
{
	EPtr res;
	if (m_s[0]=='#')
	{	new (res) HashExpr((char *)m_s);
		nextWord();		
		m_dynamic=1;
	}
	return res;
}

EPtr TyleParser::parseOperand()
{
  EPtr res, psd (parseTypeSelectionExpr() );

  if (!(res=parseBlock()))
  if (!(res=parseString()))
  if (!(res=parseNumber()))
  if (!(res=parseVar()))
  	res=parseHash();

  if (!!psd)
  { ((TypeSelectionExpr *)&*psd)->a=res;
		m_dynamic=1;
    return psd;
  }
  else return res;
	
}

//#define RetObj(x) { EPtr res; new (res) x; return res; }

#define ENDFUNC }
#define PARSEFUNC(x) EPtr TyleParser::parse##x() {
#define BINARY_BEGIN \
  { EPtr cur(father()); \
  if ( !cur ) return EPtr();\
  while (true) {
#define BINARY_END \
    else break; \
  } return cur; \
}
#define BINARY_BEGIN_RIGHT(x) \
  { EPtr cur(x()); \
  if ( !cur ) return EPtr();
#define BINARY_END_RIGHT \
  return cur;\
}
#define CREATE_BIN_ITEM(x) { m_dynamic=1; EPtr prev(cur); EPtr f(father()); pcheck(f); new (cur) x(prev,f); }
#define NEXT_CREATE_BIN_ITEM(x) { nextWord(); CREATE_BIN_ITEM(x); }
#define NEXT_CREATE_SUB_BIN_ITEM(x) { session.m_funcLevel++; NEXT_CREATE_BIN_ITEM(x); session.m_funcLevel--;}

#define BINARY_ITEM(str,x) if (parseWord(str)) CREATE_BIN_ITEM(x)

PARSEFUNC(Index)
#define father parseOperand
BINARY_BEGIN
		bool isBracket=parseWord("[");
	  if ( isBracket || parseWord("[:") )
	  { EPtr prev(cur);
	  	bool isAlt=!isBracket || parseWord(":");
			m_dynamic=1;
  	  if ( parseWord("]") )
      { new (cur) StructNameExpr(prev);
      }
      else
			{ EPtr i( parseExpr() );
  	    pcheck(i);
				if (isAlt)
  	    	new (cur) IndexAltExpr(prev,i);
				else
  	    	new (cur) IndexExpr(prev,i);
  	    if (!parseWord("]")) throw("Missing ']'.");
      }
	  }
	  else if ( parseWord("!") )
		{ EPtr prev(cur);
			m_dynamic=1;
		  new (cur) EvalExpr(prev);
	  }
	  else if ( parseWord(".*") )
	  { EPtr prev(cur);
			m_dynamic=1;
      new (cur) StructElemsExpr(prev);
		}
	  else 
		{	bool di=parseWord(".@");
			if (di || parseWord(".") )
		  { EPtr prev(cur);
				m_dynamic=1;
		  	unsigned char c=m_s[0];
		  	if ( isIdentifier(c) )
		  	{ String name((char *)m_s);
					nextWord();
		    	if (di) new (cur) StructIndexingNumberExpr(prev, name);
		      else new (cur) StructIndexingExpr(prev,name);
	    	} else if (di) 
		      	new (cur) StructLengthExpr(prev);
	    	else throw("Unexpected after '.'");
		  }
		  else if ( parseWord("->") )
	  	{ EPtr prev(cur);
				m_dynamic=1;
				String name((char *)m_s);
		  	if ( isIdentifier(m_s[0]) )
		    	nextWord();
	    	else throw("Unexpected after '.'");
				EPtr res(parseBlock());
	    	if (!res)
		    	new (cur) HeadStructIndexingExpr(prev,name);
				else
	    		new (cur) HeadCallExpr(prev,res,name);
	    }
		  else
		  {	EPtr res(parseBlock());
		    if (!res) break;
		  	{	EPtr prev(cur);
					m_dynamic=1;
			   	new (cur) ApplyExpr(res, prev);
		   	}
		  }
		}
	}
  return cur;
}
ENDFUNC

//todo: this must all change as soon as real compiler comes, because then the parse tree is just stored.
PARSEFUNC(Unary)
#undef father
#define father parseIndex
#define UNARY_ITEM(i,x,expr) case i: expr; nextWord(); pcheck(f=parseUnary()); new (r) x##Expr(f); break;
#define UNARY_ITEM_DYN(i,x) UNARY_ITEM(i,x,m_dynamic=1)
  EPtr f,r;
  if(m_s[1]==0)
  {
    switch(m_s[0])
    {
    UNARY_ITEM('&',Reference,  ) 
    UNARY_ITEM_DYN('!',Inverse    )
    UNARY_ITEM_DYN('-',Negate     )
    UNARY_ITEM_DYN('@',Length     )
    UNARY_ITEM_DYN('*',DeReference)
    UNARY_ITEM_DYN('~',BitNot     )
    default: return father();
    }
  }
  else if (parseWord("@@")) { m_dynamic=1; pcheck(f=parseUnary()); new (r) TypeExpr(f); }
  else if (parseWord("*!")) { m_dynamic=1; pcheck(f=parseUnary()); new (r) ValueExpr(f); }
  else return father();
  return r;
ENDFUNC

EPtr TyleParser::parseBinary(int level)
{
  EPtr cur(parseUnary());
  if ( !cur ) return EPtr();
  return parseBinaryOp(cur,level);
}
#define BINITEM(x) \
{ if (level##x<level) \
  { m_dynamic=1; \
		nextWord(); \
    EPtr prev(cur); EPtr f(parseBinary(level##x)); pcheck(f); new (cur) x##Expr(prev,f); \
    break; \
  } \
}

EPtr TyleParser::parseBinaryOp(EPtr cur, int level)
{
  while (true)
  {
    switch(m_s[0])
    {
    case '&':
      if(m_s[1]==0) BINITEM(BitAnd) else if (m_s[1]=='&' && m_s[2]==0) BINITEM(And) 
      return cur;
    case '|':
      if(m_s[1]==0) BINITEM(BitOr) else if (m_s[1]=='|' && m_s[2]==0) BINITEM(Or)
      return cur;
    case '^': 
      if (m_s[1]==0) BINITEM(BitXor) 
      return cur; 
    case '=': 
      if (m_s[1]=='=' && m_s[2]==0) BINITEM(Equal) 
      return cur; 
    case '!': 
      if (m_s[1]=='=' && m_s[2]==0) BINITEM(Unequal)
      return cur; 
    case '<': 
      if (m_s[1]==0) BINITEM(Smaller) else if (m_s[2]==0) 
      { if (m_s[1]=='=') BINITEM(SmallerEqual)
        else if (m_s[1]=='<' ) BINITEM(ShiftLeft)
      }
      return cur; 
    case '>': 
      if (m_s[1]==0) BINITEM(Greater) else if (m_s[2]==0) 
      { if (m_s[1]=='=') BINITEM(GreaterEqual)
        else if (m_s[1]=='>') BINITEM(ShiftRight)
      }
      return cur; 
    case '+': 
      if (m_s[1]==0) BINITEM(Add) else if (m_s[2]==0) 
      { if (m_s[1]=='>') BINITEM(Add) // deprecated
        else if (m_s[1]=='<') BINITEM(Prepend)
      }
      return cur; 
    case ':': 
      if (m_s[2]==0) 
      { if (m_s[1]=='+') BINITEM(InsertAt)
        else if (m_s[1]=='-') BINITEM(RemoveAt)
      }
      return cur; 
    case '-': 
      if (m_s[1]==0) BINITEM(Sub)
      return cur; 
    case '*': 
      if (m_s[1]==0) BINITEM(Mul)
      return cur; 
    case '/': 
      if (m_s[1]==0) BINITEM(Div)
      return cur; 
    case '%': 
      if (m_s[1]==0) BINITEM(Mod)
      return cur; 
    case '@': 
      if (m_s[1]==0) BINITEM(FindIndex)
      return cur; 
    default: return cur;
    }
  }
}
#undef BINITEM

PARSEFUNC(Switch)
#undef father
#define father parseSwitch
BINARY_BEGIN_RIGHT(parseBinary)
  if (m_s[0]=='?')
  { if (m_s[1]=='!' && m_s[2]==0) NEXT_CREATE_BIN_ITEM(WhileExpr)
    else if (m_s[1]==0)
    { nextWord();
			m_dynamic=1;
      EList l;
      EList::P lp(&l);
      do
      { lp->prepend(father()); lp++;
      } while (parseWord(":"));
      EPtr prev=cur;
      new (cur) SwitchOnExpr(prev, l );
    }
  }
BINARY_END_RIGHT
ENDFUNC

PARSEFUNC(Param)
#undef father
#define father parseSwitch
	EPtr res;
  EPtr *next=&res;
  int depth=0, pushes=0;
  try {
		for (;parseWord("<");depth++)
	  {	List<TypeFunc> structFuncs;
			structing.funcs=&structFuncs;
			List<StructElem> ses;
			TypeFunc *subFunc = 0;
			TypePtr subType;
			bool commaCame=false;
	    int i=0;
			TypePtr tp;
	  	new (tp) Type();
			if (!parseWord(">"))
	    { 
				for(;;)
		    {
					subType =parseTypeSelection(subFunc);
					if ( (!!subFunc || !!subType) && i==0 && parseWord(">")) 
						break;
			  	if (!isIdentifier(m_s[0])) 
			  	{	delete subFunc;
						throw("Expected identifier.");
	  			}
		      String m_sc((char *)m_s);
					addStructElem(ses,tp,m_sc,subType,subFunc);i++;
			  	nextWord();
			  	bool comma=parseWord(",");
			  	commaCame|=comma;
				  if (parseWord(">")) break;
			  	if (!comma) throw("Expected ',' or '>'.");
	  		}
			}
			if ( ( i==0 && (!!subFunc || !!subType)) || ( i==1 && !commaCame ) )
			{	SingleParamScope::Ptr scope;	
	  		new (scope) SingleParamScope(i==0 ? "" : ses[0].m_name , depth-session.m_funcLevel);
		    session.push(scope); pushes++;
				if (!!subFunc)
					structFuncs.last().erase();
				else if (!!subType)
					subFunc = new TypeSelection(subType);
		    next= & ( new (*next) SingleParamAssignmentExpr( subFunc, structFuncs, scope ) ) ->a;
			}
			else
			{	// multiple or null
				tp->set(ses,false);
				ParamSetScope::Ptr scope;
	  		new (scope) ParamSetScope(tp,depth-session.m_funcLevel);
		    session.push(scope); pushes++;
		    next = & ( new (*next) ParamSetAssignmentExpr( structFuncs, scope ) ) ->a ;	    
			}
	  }
	
	  *next = father();
	
	  if (!*next && next!=&res)
			throw("Expected expression.");
	  while(--pushes>=0) session.pop();
	} catch(const char *error)
	{
	  while(--pushes>=0) session.pop();
		throw(error);
	}
  return res;
ENDFUNC

// right recursive:
PARSEFUNC(Iterators)
#undef father
#define father parseIterators
BINARY_BEGIN_RIGHT(parseParam)
  if (m_s[2]==0)
  { if(m_s[1]=='!')
    {
      if (m_s[0]=='.') NEXT_CREATE_SUB_BIN_ITEM(ActOnExpr)
      else if (m_s[0]==':') NEXT_CREATE_SUB_BIN_ITEM(ActOnMultiExpr)
      else if (m_s[0]=='%') NEXT_CREATE_SUB_BIN_ITEM(ActOnColumnsExpr)
    }
    else if (m_s[0]==':' && m_s[1]=='@') NEXT_CREATE_SUB_BIN_ITEM(IndexQueryExpr)
    else if (m_s[0]=='.' && m_s[1]=='?') 
    { int ol=session.m_funcLevel; session.m_funcLevel=1; 
      NEXT_CREATE_BIN_ITEM(ActAbstractExpr)
      session.m_funcLevel=ol;
    }
  }
BINARY_END_RIGHT
ENDFUNC

// unary
PARSEFUNC(Modify)
#undef father
#define father parseIterators
  EPtr f,r;
  if (parseWord("?")) 
  { int ol=session.m_funcLevel; session.m_funcLevel=0; 
		int oldyn=m_dynamic; // no need to set m_dynamic to 0
		ClosureScope::Ptr scope;
	  new (scope) ClosureScope(ol);
	  session.push(scope);
	  try
		{
	    pcheck(f=parseModify());  
		} catch(const char *error)
		{
	    session.pop();
	    throw(error);
		}
    session.pop();
    if (((ClosureScope &)*scope).m_count)
    {	new (r) ClosuredExprExpr(f, scope);
			m_dynamic=true;
  	}
	  else
		{ new (r) ConstExpr(NEW_OBJ ExprObject(f));
			m_dynamic=oldyn;
		}
    session.m_funcLevel=ol; 
  }
  else if (parseWord(".?")) { m_dynamic=1; pcheck(f=parseModify()); new (r) DescribeExpr(f); }
  else return father();
  return r;
ENDFUNC

// right recursive:
PARSEFUNC(Assign)
#undef father
#define father parseAssign
BINARY_BEGIN_RIGHT(parseModify)
  BINARY_ITEM("=",AssignmentExpr )
  else if (m_s[1]=='=' && m_s[2]==0)
  { switch(m_s[0])
    {
    case '*': NEXT_CREATE_BIN_ITEM(MulAssignExpr); break;
    case '/': NEXT_CREATE_BIN_ITEM(DivAssignExpr); break;
    case '%': NEXT_CREATE_BIN_ITEM(ModAssignExpr); break;
    case '+': NEXT_CREATE_BIN_ITEM(AddAssignExpr); break;
    case '-': NEXT_CREATE_BIN_ITEM(SubAssignExpr); break;
    case '|': NEXT_CREATE_BIN_ITEM(BitOrAssignExpr);  break;
    case '&': NEXT_CREATE_BIN_ITEM(BitAndAssignExpr); break;
    case '^': NEXT_CREATE_BIN_ITEM(BitXorAssignExpr); break;
    default: break;
    }
  }
  else if (m_s[2]=='=' && m_s[3]==0)
  {      if( m_s[0]=='>' && m_s[1]=='>' ) NEXT_CREATE_BIN_ITEM(ShiftRightAssignExpr )
    else if( m_s[0]=='<' && m_s[1]=='<' ) NEXT_CREATE_BIN_ITEM(ShiftLeftAssignExpr )
    else if( m_s[0]=='+' && m_s[1]=='>' ) NEXT_CREATE_BIN_ITEM(AddAssignExpr ) // deprecated
    else if( m_s[0]=='+' && m_s[1]=='<' ) NEXT_CREATE_BIN_ITEM(PrependAssignExpr )
    else if( m_s[0]==':' && m_s[1]=='+' ) NEXT_CREATE_BIN_ITEM(InsertAtAssignExpr )
    else if( m_s[0]==':' && m_s[1]=='-' ) NEXT_CREATE_BIN_ITEM(RemoveAtAssignExpr )
    else if( m_s[0]=='&' && m_s[1]=='&' ) NEXT_CREATE_BIN_ITEM(AndAssignExpr )
    else if( m_s[0]=='|' && m_s[1]=='|' ) NEXT_CREATE_BIN_ITEM(OrAssignExpr )
  }
BINARY_END_RIGHT
ENDFUNC

EPtr TyleParser::parseSequence()
{
#undef father
#define father parseExpr
	int oldDynamic=m_dynamic;
	m_dynamic=0;
  EPtr res;
  SequenceExpr *s=new (res) SequenceExpr();
	LocalVarVectorQueue::Ptr queue;
  new (queue) LocalVarVectorQueue();
	session.push(queue);
	try
	{
		SequenceExpr::P sp(&(s->m_elements));
	  bool kr;
	  do
	  { kr = false;
	  	EPtr j=father();
	    if (!!j) { sp->prepend(j); sp++; kr = true;}
	    if (parseWord(",")) // this is actually a list
	    {	EList el; 
	    	el.take(s->m_elements);
		    ListExpr *l=new (res) ListExpr();
				ListExpr::P ep(&(l->m_elements));
		    FOREACH(EList, el, i)
	    	{	ep->prepend(ListExpr::Elem(*i,kr&&!i.next())); ep++;
	    	}
			  for(;;)
			  { EPtr j=father();
					if ( parseWord(","))     { if(!!j) {ep->prepend(ListExpr::Elem(j,true)); ep++; } }
			    else if (parseWord(";")) { if(!!j) {ep->prepend(ListExpr::Elem(j,false)); ep++; } }
			    else                     { if(!!j) {ep->prepend(ListExpr::Elem(j,true)); ep++; } break; }
	    	}
			  session.lvvqPop();
			  l->setQueue(queue);
				if (!m_dynamic)
				{
					Object *o=res->evaluateToPersistCopy();
					new (res) ConstExpr(o);
					m_dynamic = oldDynamic;
				}
			  return res;
	    }
	  } while (parseWord(";"));
	  s->keepResult=kr;
	  if (!s->m_elements)
		{	res = session.m_exprNull;
			session.lvvqPop();
		}
		else if ( !session.lvvqPop() && s->m_elements.length()==1 && kr )
	  { res = *(s->m_elements);
	  } else s->setQueue(queue);
		m_dynamic |= oldDynamic;
	} catch(const char *error)
	{	session.lvvqPop();
		throw(error);
	}
  return res;
}

EPtr TyleParser::finishParseList()
#undef father
#define father parseExpr
{ 
	int oldDynamic=m_dynamic;
	m_dynamic=0;
  EPtr res;
	ListExpr *s=new (res) ListExpr();
	LocalVarVectorQueue::Ptr queue;
	new (queue) LocalVarVectorQueue();
  session.push(queue);
	try
	{
	  ListExpr::P ep(&(s->m_elements));
	  while(!parseWord("}"))
	  { EPtr j=father();
	    if ( parseWord("}"))     { if(!!j) {ep->prepend(ListExpr::Elem(j,true)); ep++; } break; }
	    if ( parseWord(","))     { if(!!j) {ep->prepend(ListExpr::Elem(j,true)); ep++; } }
	    else if (parseWord(";")) { if(!!j) {ep->prepend(ListExpr::Elem(j,false)); ep++; } }
	    else throw("Expected ',',';' or '}'.");
	  }
	  session.lvvqPop();
	  s->setQueue(queue);
		if (!m_dynamic)
		{	
			if (!s->m_elements)
				res = session.m_exprEmptyList;
			else
			{	Object *o=res->evaluateToPersistCopy();
				new (res) ConstExpr(o);
			}
			m_dynamic = oldDynamic;
		}
	} catch(const char *error)
	{	session.lvvqPop();
		throw(error);
	}
	return res;
}

EPtr TyleParser::finishParseSequence()
{
  EPtr res;
  res = parseSequence();
  if (!parseWord(")")) throw("Expected ')'.");
  return res;
}

EPtr TyleParser::finishMap()
{
	int oldDynamic=m_dynamic;
	m_dynamic=0;

  EPtr res;
  MapExpr *s=new (res) MapExpr();

	List<EPtr>::P lp(&(s->m_elements));

  for(;;)
  { EPtr a(parseExpr());
    if (!a)
    { if (!parseWord("}")) throw("Expected '}'");
      break;
    }
    lp->prepend(a);lp++;
    EPtr b;
    if ( parseWord("=>")) 
    { b=parseExpr();
      if (!b) throw("Expected a expression");
    }  
    lp->prepend(b);lp++; 
    if ( parseWord("}")) break;
    if ( !parseWord(",")) throw("Expected ','");
  }
	if (!m_dynamic)
	{	
		if (!s->m_elements)
			res = session.m_exprEmptyMap;
		else
		{	Object *o=res->evaluateToPersistCopy();
			new (res) ConstExpr(o);
		}
		m_dynamic = oldDynamic;
	}
  return res;
}

PARSEFUNC(Block)
  EPtr res;
  if (parseWord("{")) res = finishParseList();
  else if (parseWord("(")) res = finishParseSequence();
  else if ( parseWord("{:") ) res = finishMap();
  return res;
ENDFUNC
